#import "GoodpromiseIapPlugin.h"
#import <StoreKit/StoreKit.h>
#import <Photos/Photos.h>

// 内购与flutter的通道名称
static NSString * const IAPMethodChannelName = @"goodpromise.exechina.com/IAP_vip_annual";
static NSString * const IAPEventChannelName  = @"goodpromise.exechina.com/IAP_vip_annual_result";

@interface GoodpromiseIapPlugin () <SKPaymentTransactionObserver, SKProductsRequestDelegate, FlutterStreamHandler>

@property (nonatomic, assign) BOOL                  onPayingFlag;       // 是否正在支付中
@property (nonatomic, copy) NSString                *currentProductId;  // 当前发起支付的id
@property (nonatomic, assign) BOOL                  isProduction;       // 是否是生产环境

@property (nonatomic, copy) FlutterEventSink        eventSink;

@end

@implementation GoodpromiseIapPlugin

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar
{
    GoodpromiseIapPlugin* instance = [[GoodpromiseIapPlugin alloc] init];
    
    FlutterMethodChannel* methodChannel = [FlutterMethodChannel methodChannelWithName:IAPMethodChannelName binaryMessenger:[registrar messenger]];
    [registrar addMethodCallDelegate:instance channel:methodChannel];

    FlutterEventChannel* streamChannel = [FlutterEventChannel eventChannelWithName:IAPEventChannelName binaryMessenger:[registrar messenger]];
    [streamChannel setStreamHandler:instance];

    // 检测一下订单
    dispatch_after(DISPATCH_TIME_NOW + (int64_t)(5.0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        [instance checkPastTransactions];
    });
}

- (instancetype)init
{
    if (self = [super init]) {
        self.onPayingFlag = false;
#if DEBUG
        self.isProduction = false;
#else
        self.isProduction = true;
#endif
        [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    }
    return self;
}

- (void)submitIAPRequest:(NSString *)productId
{
    if (self.onPayingFlag == true) {
        [self handleResult:false productId:productId transactionId:nil receipt:nil errMsg:@"正在支付中, 请等待..."];
        return;
    }
    // 标记正在支付
    self.onPayingFlag = true;
    
    // 检测是否允许内购
    if ([SKPaymentQueue canMakePayments]) {
        self.currentProductId = [productId copy];
        NSSet *productSet = [NSSet setWithArray:@[productId]];
        SKProductsRequest *productRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productSet];
        productRequest.delegate = self;
        [productRequest start];
    }
    // 已禁止内购
    else {
        NSLog(@"设备、当前系统不支持或者处于家长模式下，无法使用内购");
        self.onPayingFlag = false;
        [self handleResult:false productId:productId transactionId:nil receipt:nil errMsg:@"设备、当前系统不支持或者处于家长模式下，无法使用内购"];
    }
}

// 开始调起支付的时候，需提前检测一下订单，将已完成的订单结束交易。
- (void)checkPastTransactions
{
    NSArray<SKPaymentTransaction *> *transactions = [SKPaymentQueue defaultQueue].transactions;
    if (transactions.count > 0 && [SKPaymentQueue canMakePayments]) {
        [self paymentQueue:[SKPaymentQueue defaultQueue] updatedTransactions:transactions];
    }
}

- (void)handleResult:(BOOL)success productId:(NSString * _Nonnull)productId transactionId:(NSString * _Nullable)transactionId receipt:(NSString * _Nullable)receipt errMsg:(NSString * _Nullable)errMsg
{
    NSString *productIdifier = (productId == nil ? @"" : productId);
    NSString *transactionIdifier = (transactionId == nil ? @"" : transactionId);
    NSString *receiptString = (receipt == nil ? @"" : receipt);
    NSDictionary *result = @{
        @"result": @(success),
        @"isProduction": @(self.isProduction),
        @"productId": productIdifier,
        @"transactionId": transactionIdifier,
        @"receipt": receipt == nil ? @"" : receiptString,
        @"errMsg": @"交易完成"
    };
    if (self.eventSink) {
        self.eventSink(result);
    }
}

#pragma mark ================ SKProductsRequestDelegate ================

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    SKProduct *requestProduct = nil;
    for (SKProduct *product in response.products) {
        if ([product.productIdentifier isEqualToString:self.currentProductId]) {
            requestProduct = product;
        }
    }
    if (requestProduct) {
        NSLog(@"开始下单");
        SKPayment *payment = [SKPayment paymentWithProduct:requestProduct];
        [[SKPaymentQueue defaultQueue] addPayment:payment];
    }
    else {
        NSLog(@"没有查询到相应的产品信息: %@", self.currentProductId);
        self.onPayingFlag = false;
        [self handleResult:false productId:self.currentProductId transactionId:nil receipt:nil errMsg:@"没有查询到相应的产品信息"];
        self.currentProductId = nil;
    }
}

- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
    NSLog(@"请求内购失败: %@", error);
    self.onPayingFlag = false;
    [self handleResult:false productId:self.currentProductId transactionId:nil receipt:nil errMsg:@"请求内购失败"];
    self.currentProductId = nil;
}

#pragma mark ================ SKPaymentTransactionObserver ================

// Sent when the transaction array has changed (additions or state changes).  Client should check state of transactions and finish as appropriate.
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions
{
    for (SKPaymentTransaction *transaction in transactions) {
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchased:
            {
                NSLog(@"交易完成, 收到内购收据, 交给服务器验证");
                // 结束交易
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                // 获取收据
                NSData *data = [NSData dataWithContentsOfFile:[[[NSBundle mainBundle] appStoreReceiptURL] path]];
                NSString *receipt = [data base64EncodedStringWithOptions:0];
                NSLog(@"内购收据: %@", receipt);
                [self handleResult:true productId:transaction.payment.productIdentifier transactionId:transaction.transactionIdentifier receipt:receipt errMsg:@"交易完成"];
                self.currentProductId = nil;
                self.onPayingFlag = false;
                
                break;
            }
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"交易中");
                break;
            case SKPaymentTransactionStateRestored:
                NSLog(@"恢复购买");
                break;
            case SKPaymentTransactionStateFailed:
            {
                NSLog(@"交易失败：%@", transaction.error);
                self.onPayingFlag = false;
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                
                if (transaction.payment.productIdentifier == self.currentProductId) {
                    [self handleResult:false productId:self.currentProductId transactionId:nil receipt:nil errMsg:@"交易失败"];
                    self.currentProductId = nil;
                }
                break;
            }
            case SKPaymentTransactionStateDeferred: {
                NSLog(@"最终状态是等待支付，未知错误");
                self.onPayingFlag = false;
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                
                if (transaction.payment.productIdentifier == self.currentProductId) {
                    [self handleResult:false productId:self.currentProductId transactionId:nil receipt:nil errMsg:@"交易失败, 未知错误"];
                    self.currentProductId = nil;
                }
            }
                break;
            default:
                break;
        }
    }
}

#pragma mark ================ FlutterPlugin ================

- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
{
    if ([@"submitIAPRequest" isEqualToString:call.method]) {
        NSString *productId = call.arguments;
        if (productId == nil || ![productId isKindOfClass:[NSString class]] || productId.length == 0) {
            if (result) {
                result([FlutterError errorWithCode:@"no product id"
                                           message:@"please give me a product id with String"
                                           details:nil]);
            }
        }
        else {
            [self submitIAPRequest:productId];
        }
    }
    else if ([@"checkPermission" isEqualToString:call.method]) {
        NSString *permission = call.arguments;
        NSInteger status = 0;
        if ([permission isEqualToString:@"photos"]) {
            if (@available(iOS 14, *)) {
                status = [PHPhotoLibrary authorizationStatusForAccessLevel:PHAccessLevelReadWrite];
            } else {
                status = [PHPhotoLibrary authorizationStatus];
            }
            if (result) {
                result(@(status));
            }
        }
        else if ([permission isEqualToString:@"photosAddOnly"]) {
            if (@available(iOS 14, *)) {
                status = [PHPhotoLibrary authorizationStatusForAccessLevel:PHAccessLevelAddOnly];
            } else {
                status = [PHPhotoLibrary authorizationStatus];
            }
            if (result) {
                result(@(status));
            }
        }
        else {
            if (result) {
                result(@(2));
            }
        }
    }
    else {
        if (result) {
            result(FlutterMethodNotImplemented);
        }
    }
}

#pragma mark ================ FlutterStreamHandler ================

- (FlutterError * _Nullable)onCancelWithArguments:(id _Nullable)arguments
{
    self.eventSink = nil;
    return nil;
}

- (FlutterError * _Nullable)onListenWithArguments:(id _Nullable)arguments eventSink:(nonnull FlutterEventSink)events
{
    self.eventSink = events;
    return nil;
}

@end
